<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/blog/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/blog/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/blog/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/blog/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/blog/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/blog/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT" />










<meta name="description" content="####1. APP加固 ######1). 原理加密过程的三个对象:  1、需要加密的Apk(源Apk) 2、壳程序Apk(负责解密Apk工作) 3、加密工具(将源Apk进行加密和壳Dex合并成新的Dex)">
<meta name="keywords" content="Android、iOS、Web、React Native">
<meta property="og:type" content="article">
<meta property="og:title" content="Android-DEX加壳">
<meta property="og:url" content="http://yoursite.com/blog/2018/08/06/Android-Plugin/Android-DEX加壳/index.html">
<meta property="og:site_name" content="凌浩雨_博客">
<meta property="og:description" content="####1. APP加固 ######1). 原理加密过程的三个对象:  1、需要加密的Apk(源Apk) 2、壳程序Apk(负责解密Apk工作) 3、加密工具(将源Apk进行加密和壳Dex合并成新的Dex)">
<meta property="og:locale" content="default">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-0a9b5f7d8499b804.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-d8ccadc0924e7706.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-4aea8ae8a743d763.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-a332c747dc92610e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-b4d39ce0f7aa85a7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-0e9bed3e7bed93c4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-0657ef7a7e095569.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-60ae83dfbed3b90b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-343da0fd7b7f4b1f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-1a824528a41d5526.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-9b2e9fb6ecb5198d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/3110861-d958a836f5f45ca6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:updated_time" content="2018-08-06T11:10:38.866Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Android-DEX加壳">
<meta name="twitter:description" content="####1. APP加固 ######1). 原理加密过程的三个对象:  1、需要加密的Apk(源Apk) 2、壳程序Apk(负责解密Apk工作) 3、加密工具(将源Apk进行加密和壳Dex合并成新的Dex)">
<meta name="twitter:image" content="https://upload-images.jianshu.io/upload_images/3110861-0a9b5f7d8499b804.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/blog/',
    scheme: 'Pisces',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: 'Author'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/blog/2018/08/06/Android-Plugin/Android-DEX加壳/"/>





  <title>Android-DEX加壳 | 凌浩雨_博客</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="default">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/blog/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">凌浩雨_博客</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/blog/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/blog/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            Archives
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/blog/blog/2018/08/06/Android-Plugin/Android-DEX加壳/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="凌浩雨">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/blog/images/avatar.jpeg">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="凌浩雨_博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">Android-DEX加壳</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">Posted on</span>
              
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2018-08-06T18:01:38+08:00">
                2018-08-06
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>####1. APP加固</p>
<p>######1). 原理<br><img src="https://upload-images.jianshu.io/upload_images/3110861-0a9b5f7d8499b804.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图1.png"><br>加密过程的三个对象:</p>
<ul>
<li>1、需要加密的Apk(源Apk)</li>
<li>2、壳程序Apk(负责解密Apk工作)</li>
<li>3、加密工具(将源Apk进行加密和壳Dex合并成新的Dex)</li>
</ul>
<a id="more"></a>
<p>######2). DEX头内容<br><img src="https://upload-images.jianshu.io/upload_images/3110861-d8ccadc0924e7706.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图2.png"><br>需要关注的字段：</p>
<ul>
<li>checksum 文件校验码 ，使用alder32 算法校验文件除去 maigc ，checksum 外余下的所有文件区域 ，用于检查文件错误 。</li>
<li>signature 使用 SHA-1 算法 hash 除去 magic ,checksum 和 signature 外余下的所有文件区域 ，用于唯一识别本文件 。</li>
<li>fileSize Dex 文件的大小 。</li>
<li>在文件的最后，我们需要标注被加密的apk的大小，因此需要增加4个字节。<br><img src="https://upload-images.jianshu.io/upload_images/3110861-4aea8ae8a743d763.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图3.png"></li>
</ul>
<p>######3). 解密过程<br>宿主Apk启动 -&gt; 宿主Application中解密Apk -&gt; 替换ClassLoader -&gt; 替换资源路径 -&gt; 替换Application对象</p>
<p>####2. 源程序Module(source)</p>
<p>######1). SourceApplication<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 源Apk的全局Application</span><br><span class="line"> * Created by mazaiting on 2018/6/26.</span><br><span class="line"> */</span><br><span class="line"></span><br><span class="line">public class SourceApplication extends Application &#123;</span><br><span class="line">  private static final String TAG = SourceApplication.class.getSimpleName();</span><br><span class="line">  @Override</span><br><span class="line">  public void onCreate() &#123;</span><br><span class="line">    super.onCreate();</span><br><span class="line">    Log.d(TAG, &quot;onCreate: --------&quot;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>######2). MainActivity<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 应用主入口</span><br><span class="line"> */</span><br><span class="line">public class MainActivity extends AppCompatActivity &#123;</span><br><span class="line">  private static final String TAG = MainActivity.class.getSimpleName();</span><br><span class="line">  @Override</span><br><span class="line">  protected void onCreate(Bundle savedInstanceState) &#123;</span><br><span class="line">    super.onCreate(savedInstanceState);</span><br><span class="line">    TextView tvContent = new TextView(this);</span><br><span class="line">    tvContent.setText(&quot;I am Source Apk&quot;);</span><br><span class="line">    tvContent.setOnClickListener(new View.OnClickListener()&#123;</span><br><span class="line">      @Override</span><br><span class="line">      public void onClick(View arg0) &#123;</span><br><span class="line">        Intent intent = new Intent(MainActivity.this, SecondActivity.class);</span><br><span class="line">        startActivity(intent);</span><br><span class="line">      &#125;&#125;);</span><br><span class="line">    setContentView(tvContent);</span><br><span class="line">    Log.i(TAG, &quot;onCreate：app:&quot;+getApplicationContext());</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>######3). 第二个页面<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 第二个页面</span><br><span class="line"> */</span><br><span class="line">public class SecondActivity extends AppCompatActivity &#123;</span><br><span class="line">  </span><br><span class="line">  @Override</span><br><span class="line">  protected void onCreate(Bundle savedInstanceState) &#123;</span><br><span class="line">    super.onCreate(savedInstanceState);</span><br><span class="line">    TextView tv_content = new TextView(this);</span><br><span class="line">    tv_content.setText(&quot;I am Second Activity&quot;);</span><br><span class="line">    setContentView(tv_content);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>######4). AndroidManifest.xml文件<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span><br><span class="line">&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;</span><br><span class="line">          package=&quot;com.mazaiting.reinforcement&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;application</span><br><span class="line">      android:name=&quot;.SourceApplication&quot;</span><br><span class="line">      android:allowBackup=&quot;true&quot;</span><br><span class="line">      android:icon=&quot;@mipmap/ic_launcher&quot;</span><br><span class="line">      android:label=&quot;@string/app_name&quot;</span><br><span class="line">      android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;</span><br><span class="line">      android:supportsRtl=&quot;true&quot;</span><br><span class="line">      android:theme=&quot;@style/AppTheme&quot;&gt;</span><br><span class="line">    &lt;activity android:name=&quot;.MainActivity&quot;&gt;</span><br><span class="line">      &lt;intent-filter&gt;</span><br><span class="line">        &lt;action android:name=&quot;android.intent.action.MAIN&quot;/&gt;</span><br><span class="line"></span><br><span class="line">        &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot;/&gt;</span><br><span class="line">      &lt;/intent-filter&gt;</span><br><span class="line">    &lt;/activity&gt;</span><br><span class="line">    &lt;activity android:name=&quot;.SecondActivity&quot;&gt;</span><br><span class="line">    &lt;/activity&gt;</span><br><span class="line">  &lt;/application&gt;</span><br><span class="line"></span><br><span class="line">&lt;/manifest&gt;</span><br></pre></td></tr></table></figure></p>
<p>######5). 签名<br>Build -&gt; Generate Signed APK，对应用进行签名（如果没有keystore, 可以创建一个新的），将签名后的apk文件放置在项目根目录下的force文件夹下，并更名为source.apk<br><img src="https://upload-images.jianshu.io/upload_images/3110861-a332c747dc92610e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图3.png"><br><img src="https://upload-images.jianshu.io/upload_images/3110861-b4d39ce0f7aa85a7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图4.png"></p>
<p>####3. 脱壳Module(reforceapk)</p>
<p>######1). 替换步骤<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">* 代理Application</span><br><span class="line">* 步骤：</span><br><span class="line">*    ------- 在attachBaseContext -------</span><br><span class="line">*    1. 从当前APK中拿到classes.dex文件，拿到classes.dex文件的二进制数据</span><br><span class="line">*    2. 从dex的二进制数据中分离出解密后的apk，及so文件</span><br><span class="line">*    3. 反射获取主线程对象，并从中获取所有已加载的package信息，找到当前LoadApk的弱引用</span><br><span class="line">*    4. 创建一个新的DexClassLoader，从指定路径加载apk资源</span><br><span class="line">*    5. 加载被加密的apk主Activity入口</span><br><span class="line">*    -------  在onCreate方法   ----------</span><br><span class="line">*    6. 获取配置在清单文件的源apk的Application</span><br><span class="line">*    7. 替换原有的Application</span><br><span class="line">*    8. 调用被加密app的Application</span><br></pre></td></tr></table></figure></p>
<p>######2). 代码<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 代理Application</span><br><span class="line"> * 步骤：</span><br><span class="line"> *    ------- 在attachBaseContext -------</span><br><span class="line"> *    1. 从当前APK中拿到classes.dex文件，拿到classes.dex文件的二进制数据</span><br><span class="line"> *    2. 从dex的二进制数据中分离出解密后的apk，及so文件</span><br><span class="line"> *    3. 反射获取主线程对象，并从中获取所有已加载的package信息，找到当前LoadApk的弱引用</span><br><span class="line"> *    4. 创建一个新的DexClassLoader，从指定路径加载apk资源</span><br><span class="line"> *    5. 加载被加密的apk主Activity入口</span><br><span class="line"> *    -------  在onCreate方法   ----------</span><br><span class="line"> *    6. 获取配置在清单文件的源apk的Application</span><br><span class="line"> *    7. 替换原有的Application</span><br><span class="line"> *    8. 调用被加密app的Application</span><br><span class="line"> * Created by mazaiting on 2018/6/26.</span><br><span class="line"> */</span><br><span class="line"></span><br><span class="line">public class ProxyApplication extends Application &#123;</span><br><span class="line">  private static final String TAG = ProxyApplication.class.getSimpleName();</span><br><span class="line">  /**</span><br><span class="line">   * APP_KEY获取Activity入口</span><br><span class="line">   */</span><br><span class="line">  private static final String APP_KEY = &quot;APPLICATION_CLASS_NAME&quot;;</span><br><span class="line">  /**ActivityThread包名*/</span><br><span class="line">  private static final String CLASS_NAME_ACTIVITY_THREAD = &quot;android.app.ActivityThread&quot;;</span><br><span class="line">  /**LoadedApk包名*/</span><br><span class="line">  private static final String CLASS_NAME_LOADED_APK = &quot;android.app.LoadedApk&quot;;</span><br><span class="line">  /**</span><br><span class="line">   * 源Apk路径</span><br><span class="line">   */</span><br><span class="line">  private String mSrcApkFilePath;</span><br><span class="line">  /**</span><br><span class="line">   * odex路径</span><br><span class="line">   */</span><br><span class="line">  private String mOdexPath;</span><br><span class="line">  /**</span><br><span class="line">   * lib路径</span><br><span class="line">   */</span><br><span class="line">  private String mLibPath;</span><br><span class="line">  /**</span><br><span class="line">   * 加载资源</span><br><span class="line">   */</span><br><span class="line">  protected AssetManager mAssetManager;</span><br><span class="line">  protected Resources mResources;</span><br><span class="line">  protected Resources.Theme mTheme;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 最先执行的方法</span><br><span class="line">   */</span><br><span class="line">  @Override</span><br><span class="line">  protected void attachBaseContext(Context base) &#123;</span><br><span class="line">    super.attachBaseContext(base);</span><br><span class="line">    Log.d(TAG, &quot;attachBaseContext: --------onCreate&quot;);</span><br><span class="line">    </span><br><span class="line">    try &#123;</span><br><span class="line">      // 创建payload_odex和payload_lib文件夹，payload_odex中放置源apk即源dex，payload_lib放置so文件</span><br><span class="line">      File odex = this.getDir(&quot;payload_odex&quot;, MODE_PRIVATE);</span><br><span class="line">      File libs = this.getDir(&quot;payload_lib&quot;, MODE_PRIVATE);</span><br><span class="line">      // 用于存放源apk释放出来的dex</span><br><span class="line">      mOdexPath = odex.getAbsolutePath();</span><br><span class="line">      // 用于存放源apk用到的so文件</span><br><span class="line">      mLibPath = libs.getAbsolutePath();</span><br><span class="line">      // 用于存放解密后的apk</span><br><span class="line">      mSrcApkFilePath = mOdexPath + &quot;/payload.apk&quot;;</span><br><span class="line">      </span><br><span class="line">      File srcApkFile = new File(mSrcApkFilePath);</span><br><span class="line">      Log.d(TAG, &quot;attachBaseContext: apk size: &quot; + srcApkFile.length());</span><br><span class="line">      </span><br><span class="line">      // 第一次加载</span><br><span class="line">      if (!srcApkFile.exists()) &#123;</span><br><span class="line">        Log.d(TAG, &quot;attachBaseContext: isFirstLoading&quot;);</span><br><span class="line">        srcApkFile.createNewFile();</span><br><span class="line">        // 拿到dex文件</span><br><span class="line">        byte[] dexData = this.readDexFileFromApk();</span><br><span class="line">        // 取出解密后的apk放置在/payload.apk，及其so文件放置在payload_lib下</span><br><span class="line">        this.splitPayLoadFromDex(dexData);</span><br><span class="line">      &#125;</span><br><span class="line">      </span><br><span class="line">      // 配置动态加载环境</span><br><span class="line">      // 反射获取主线程对象，并从中获取所有已加载的package信息，找到当前LoadApk的弱引用</span><br><span class="line">      // 获取主线程对象</span><br><span class="line">      Object currentActivityThread = RefInvoke.invokeStaticMethod(</span><br><span class="line">              CLASS_NAME_ACTIVITY_THREAD, &quot;currentActivityThread&quot;,</span><br><span class="line">              new Class[]&#123;&#125;, new Object[]&#123;&#125;</span><br><span class="line">      );</span><br><span class="line">      // 获取当前报名</span><br><span class="line">      String packageName = this.getPackageName();</span><br><span class="line">      // 获取已加载的所有包</span><br><span class="line">      ArrayMap mPackages = (ArrayMap) RefInvoke.getFieldObject(</span><br><span class="line">              CLASS_NAME_ACTIVITY_THREAD, currentActivityThread,</span><br><span class="line">              &quot;mPackages&quot;</span><br><span class="line">      );</span><br><span class="line">      // 获取LoadApk的弱引用</span><br><span class="line">      WeakReference wr = (WeakReference) mPackages.get(packageName);</span><br><span class="line">      </span><br><span class="line">      // 创建一个新的DexClassLoader用于加载源Apk</span><br><span class="line">      // 传入apk路径，dex释放路径，so路径，及父节点的DexClassLoader使其遵循双亲委托模型</span><br><span class="line">      // 反射获取属性ClassLoader</span><br><span class="line">      Object mClassLoader = RefInvoke.getFieldObject(</span><br><span class="line">              CLASS_NAME_LOADED_APK, wr.get(), &quot;mClassLoader&quot;</span><br><span class="line">      );</span><br><span class="line">      // 定义新的DexClassLoader对象，指定apk路径，odex路径，lib路径</span><br><span class="line">      DexClassLoader dLoader = new DexClassLoader(</span><br><span class="line">              mSrcApkFilePath, mOdexPath, mLibPath, (ClassLoader) mClassLoader</span><br><span class="line">      );</span><br><span class="line">      // getClassLoader()等同于 (ClassLoader) RefInvoke.getFieldOjbect()</span><br><span class="line">      // 但是为了替换掉父节点我们需要通过反射来获取并修改其值</span><br><span class="line">      Log.d(TAG, &quot;attachBaseContext: 父ClassLoader: &quot; + mClassLoader);</span><br><span class="line">      </span><br><span class="line">      // 将父节点DexClassLoader替换</span><br><span class="line">      RefInvoke.setFieldObject(</span><br><span class="line">              CLASS_NAME_LOADED_APK,</span><br><span class="line">              &quot;mClassLoader&quot;,</span><br><span class="line">              wr.get(),</span><br><span class="line">              dLoader</span><br><span class="line">      );</span><br><span class="line">      </span><br><span class="line">      Log.d(TAG, &quot;attachBaseContext: 子ClassLoader: &quot; + dLoader);</span><br><span class="line">      </span><br><span class="line">      try &#123;</span><br><span class="line">        // 尝试加载源apk的MainActivity</span><br><span class="line">        Object actObj = dLoader.loadClass(&quot;com.mazaiting.reinforcement.MainActivity&quot;);</span><br><span class="line">        Log.d(TAG, &quot;attachBaseContext: SrcApk_MainActivity: &quot; + actObj);</span><br><span class="line">      &#125; catch (ClassNotFoundException e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">        Log.d(TAG, &quot;attachBaseContext: LoadSrcActivityErr: &quot; + Log.getStackTraceString(e));</span><br><span class="line">      &#125;</span><br><span class="line">      </span><br><span class="line">    &#125; catch (IOException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">      Log.d(TAG, &quot;attachBaseContext: error: &quot; + Log.getStackTraceString(e));</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 从Dex中分割出资源</span><br><span class="line">   *</span><br><span class="line">   * @param dexData dex资源</span><br><span class="line">   */</span><br><span class="line">  private void splitPayLoadFromDex(byte[] dexData) throws IOException &#123;</span><br><span class="line">    // 获取dex数据长度</span><br><span class="line">    int len = dexData.length;</span><br><span class="line">    // 存储被加壳apk的长度</span><br><span class="line">    byte[] dexLen = new byte[4];</span><br><span class="line">    // 获取最后4个字节数据</span><br><span class="line">    System.arraycopy(dexData, len - 4, dexLen, 0, 4);</span><br><span class="line">    ByteArrayInputStream bais = new ByteArrayInputStream(dexLen);</span><br><span class="line">    DataInputStream in = new DataInputStream(bais);</span><br><span class="line">    // 获取被加密apk的长度</span><br><span class="line">    int readInt = in.readInt();</span><br><span class="line">    // 打印被加密apk的长度</span><br><span class="line">    Log.d(TAG, &quot;splitPayLoadFromDex: Integer.toHexString(readInt): &quot; + Integer.toHexString(readInt));</span><br><span class="line">    </span><br><span class="line">    // 取出apk</span><br><span class="line">    byte[] enSrcApk = new byte[readInt];</span><br><span class="line">    // 将被加密apk内容复制到二进制数组中</span><br><span class="line">    System.arraycopy(dexData, len - 4 - readInt, enSrcApk, 0, readInt);</span><br><span class="line">    </span><br><span class="line">    // 对源apk解密</span><br><span class="line">    byte[] srcApk = decrypt(enSrcApk);</span><br><span class="line">    </span><br><span class="line">    // 写入源APK文件</span><br><span class="line">    File file = new File(mSrcApkFilePath);</span><br><span class="line">    try &#123;</span><br><span class="line">      FileOutputStream fos = new FileOutputStream(file);</span><br><span class="line">      fos.write(srcApk);</span><br><span class="line">      fos.close();</span><br><span class="line">    &#125; catch (IOException e) &#123;</span><br><span class="line">      throw new RuntimeException(e);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 分析源apk文件</span><br><span class="line">    ZipInputStream zis = new ZipInputStream(</span><br><span class="line">            new BufferedInputStream(</span><br><span class="line">                    new FileInputStream(file)</span><br><span class="line">            )</span><br><span class="line">    );</span><br><span class="line">    </span><br><span class="line">    // 遍历压缩包</span><br><span class="line">    while (true) &#123;</span><br><span class="line">      ZipEntry entry = zis.getNextEntry();</span><br><span class="line">      // 判断是否有内容</span><br><span class="line">      if (null == entry) &#123;</span><br><span class="line">        zis.close();</span><br><span class="line">        break;</span><br><span class="line">      &#125;</span><br><span class="line">      </span><br><span class="line">      // 依次取出被加壳的apk用到的so文件，放到libPath中(data/data/包名/paytload_lib)</span><br><span class="line">      String name = entry.getName();</span><br><span class="line">      if (name.startsWith(&quot;lib/&quot;) &amp;&amp; name.endsWith(&quot;.so&quot;)) &#123;</span><br><span class="line">        // 存储文件</span><br><span class="line">        File storeFile = new File(</span><br><span class="line">                mLibPath + &quot;/&quot; + name.substring(name.lastIndexOf(&apos;/&apos;))</span><br><span class="line">        );</span><br><span class="line">        storeFile.createNewFile();</span><br><span class="line">        FileOutputStream fos = new FileOutputStream(storeFile);</span><br><span class="line">        byte[] bytes = new byte[1024];</span><br><span class="line">        while (true) &#123;</span><br><span class="line">          int length = zis.read(bytes);</span><br><span class="line">          if (-1 == length) break;</span><br><span class="line">          fos.write(bytes);</span><br><span class="line">        &#125;</span><br><span class="line">        fos.flush();</span><br><span class="line">        fos.close();</span><br><span class="line">      &#125;</span><br><span class="line">      zis.closeEntry();</span><br><span class="line">    &#125;</span><br><span class="line">    zis.close();</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 解密二进制</span><br><span class="line">   *</span><br><span class="line">   * @param srcData 二进制数</span><br><span class="line">   * @return 解密后的二进制数据</span><br><span class="line">   */</span><br><span class="line">  private byte[] decrypt(byte[] srcData) &#123;</span><br><span class="line">    for (int i = 0; i &lt; srcData.length; i++) &#123;</span><br><span class="line">      srcData[i] ^= 0xFF;</span><br><span class="line">    &#125;</span><br><span class="line">    return srcData;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 从ApK文件中获取DEX文件</span><br><span class="line">   *</span><br><span class="line">   * @return dex字节数组</span><br><span class="line">   */</span><br><span class="line">  private byte[] readDexFileFromApk() throws IOException &#123;</span><br><span class="line">    ByteArrayOutputStream baos = new ByteArrayOutputStream();</span><br><span class="line">    ZipInputStream zis = new ZipInputStream(</span><br><span class="line">            new BufferedInputStream(</span><br><span class="line">                    new FileInputStream(this.getApplicationInfo().sourceDir)</span><br><span class="line">            )</span><br><span class="line">    );</span><br><span class="line">    // 遍历压缩包</span><br><span class="line">    while (true) &#123;</span><br><span class="line">      ZipEntry entry = zis.getNextEntry();</span><br><span class="line">      if (null == entry) &#123;</span><br><span class="line">        zis.close();</span><br><span class="line">        break;</span><br><span class="line">      &#125;</span><br><span class="line">      // 获取dex文件</span><br><span class="line">      if (&quot;classes.dex&quot;.equals(entry.getName())) &#123;</span><br><span class="line">        byte[] bytes = new byte[1024];</span><br><span class="line">        while (true) &#123;</span><br><span class="line">          int len = zis.read(bytes);</span><br><span class="line">          if (len == -1) break;</span><br><span class="line">          baos.write(bytes, 0, len);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      zis.closeEntry();</span><br><span class="line">    &#125;</span><br><span class="line">    zis.close();</span><br><span class="line">    return baos.toByteArray();</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  </span><br><span class="line">  @Override</span><br><span class="line">  public void onCreate() &#123;</span><br><span class="line">    super.onCreate();</span><br><span class="line">        </span><br><span class="line">    Log.d(TAG, &quot;onCreate: ---------------&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取配置在清单文件的源apk的Application路径</span><br><span class="line">    String appClassName = null;</span><br><span class="line">    try &#123;</span><br><span class="line">      // 创建应用信息对象</span><br><span class="line">      ApplicationInfo ai = this.getPackageManager().getApplicationInfo(this.getPackageName(), PackageManager.GET_META_DATA);</span><br><span class="line">      // 获取metaData数据</span><br><span class="line">      Bundle bundle = ai.metaData;</span><br><span class="line">      if (null != bundle &amp;&amp; bundle.containsKey(APP_KEY)) &#123;</span><br><span class="line">        appClassName = bundle.getString(APP_KEY);</span><br><span class="line">      &#125; else &#123;</span><br><span class="line">        Log.d(TAG, &quot;onCreate: have no application class name&quot;);</span><br><span class="line">        return;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; catch (PackageManager.NameNotFoundException e) &#123;</span><br><span class="line">      Log.d(TAG, &quot;onCreate: error: &quot; + Log.getStackTraceString(e));</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取当前Activity线程</span><br><span class="line">    Object currentActivityThread = RefInvoke.invokeStaticMethod(CLASS_NAME_ACTIVITY_THREAD,</span><br><span class="line">            &quot;currentActivityThread&quot;, new Class[]&#123;&#125;, new Object[]&#123;&#125;);</span><br><span class="line">    // 获取绑定的应用</span><br><span class="line">    Object mBoundApplication = RefInvoke.getFieldObject(CLASS_NAME_ACTIVITY_THREAD,</span><br><span class="line">            currentActivityThread, &quot;mBoundApplication&quot;);</span><br><span class="line">    // 获取加载apk的信息</span><br><span class="line">    Object loadedApkInfo = RefInvoke.getFieldObject(</span><br><span class="line">            CLASS_NAME_ACTIVITY_THREAD + &quot;$AppBindData&quot;,</span><br><span class="line">            mBoundApplication, &quot;info&quot;</span><br><span class="line">    );</span><br><span class="line">    // 将LoadedApk中的ApplicationInfo设置为null</span><br><span class="line">    RefInvoke.setFieldObject(CLASS_NAME_LOADED_APK, &quot;mApplication&quot;, loadedApkInfo, null);</span><br><span class="line">    // 获取currentActivityThread中注册的Application</span><br><span class="line">    Object oldApplication = RefInvoke.getFieldObject(</span><br><span class="line">            CLASS_NAME_ACTIVITY_THREAD, currentActivityThread, &quot;mInitialApplication&quot;</span><br><span class="line">    );</span><br><span class="line">    // 获取ActivityThread中所有已注册的Application, 并将当前壳Apk的Application从中移除</span><br><span class="line">    ArrayList&lt;Application&gt; mAllApplications = (ArrayList&lt;Application&gt;) RefInvoke.getFieldObject(</span><br><span class="line">            CLASS_NAME_ACTIVITY_THREAD, currentActivityThread, &quot;mAllApplications&quot;</span><br><span class="line">    );</span><br><span class="line">    mAllApplications.remove(oldApplication);</span><br><span class="line">    // 从loadedApk中获取应用信息</span><br><span class="line">    ApplicationInfo appInfoInLoadedApk = (ApplicationInfo) RefInvoke.getFieldObject(</span><br><span class="line">            CLASS_NAME_LOADED_APK, loadedApkInfo, &quot;mApplicationInfo&quot;</span><br><span class="line">    );</span><br><span class="line">    // 从AppBindData中获取应用信息</span><br><span class="line">    ApplicationInfo appInfoInAppBindData = (ApplicationInfo) RefInvoke.getFieldObject(</span><br><span class="line">            CLASS_NAME_ACTIVITY_THREAD + &quot;$AppBindData&quot;, mBoundApplication, &quot;appInfo&quot;</span><br><span class="line">    );</span><br><span class="line">    // 替换原来的Application</span><br><span class="line">    appInfoInLoadedApk.className = appClassName;</span><br><span class="line">    appInfoInAppBindData.className = appClassName;</span><br><span class="line">    </span><br><span class="line">    // 注册Application</span><br><span class="line">    Application app = (Application) RefInvoke.invokeMethod(</span><br><span class="line">            CLASS_NAME_LOADED_APK, &quot;makeApplication&quot;, loadedApkInfo,</span><br><span class="line">            new Class[]&#123;boolean.class, Instrumentation.class&#125;,</span><br><span class="line">            new Object[]&#123;false, null&#125;</span><br><span class="line">    );</span><br><span class="line">    // 替换ActivityThread中的Application</span><br><span class="line">    RefInvoke.setFieldObject(CLASS_NAME_ACTIVITY_THREAD, &quot;mInitialApplication&quot;,</span><br><span class="line">            currentActivityThread, app);</span><br><span class="line">    ArrayMap mProviderMap = (ArrayMap) RefInvoke.getFieldObject(</span><br><span class="line">            CLASS_NAME_ACTIVITY_THREAD, currentActivityThread, &quot;mProviderMap&quot;</span><br><span class="line">    );</span><br><span class="line">  </span><br><span class="line">    // 遍历</span><br><span class="line">    for (Object providerClientRecord : mProviderMap.values()) &#123;</span><br><span class="line">      Object localProvider = RefInvoke.getFieldObject(</span><br><span class="line">              CLASS_NAME_ACTIVITY_THREAD + &quot;$ProviderClientRecord&quot;,</span><br><span class="line">              providerClientRecord, &quot;mLocalProvider&quot;</span><br><span class="line">      );</span><br><span class="line">      RefInvoke.setFieldObject(&quot;android.content.ContentProvider&quot;, &quot;mContext&quot;,</span><br><span class="line">              localProvider, app);</span><br><span class="line">    &#125;</span><br><span class="line">  </span><br><span class="line">    Log.d(TAG, &quot;onCreate: SrcApp: &quot; + app);</span><br><span class="line">    // 调用新的Application</span><br><span class="line">    app.onCreate();</span><br><span class="line">    </span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure></p>
<p>######3). RefInvoke类<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 反射类</span><br><span class="line"> * Created by mazaiting on 2018/6/26.</span><br><span class="line"> */</span><br><span class="line"></span><br><span class="line">public class RefInvoke &#123;</span><br><span class="line">  /**</span><br><span class="line">   * 反射执行类的静态函数（public）</span><br><span class="line">   *</span><br><span class="line">   * @param className  类名</span><br><span class="line">   * @param methodName 方法名</span><br><span class="line">   * @param pareTypes  函数的参数类型</span><br><span class="line">   * @param pareValues 调用函数时传入的参数</span><br><span class="line">   * @return</span><br><span class="line">   */</span><br><span class="line">  public static Object invokeStaticMethod(String className, String methodName, Class[] pareTypes, Object[] pareValues) &#123;</span><br><span class="line">    try &#123;</span><br><span class="line">      Class objClass = Class.forName(className);</span><br><span class="line">      Method method = objClass.getMethod(methodName, pareTypes);</span><br><span class="line">      return method.invoke(null, pareValues);</span><br><span class="line">    &#125; catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    return null;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 反射执行的函数（public）</span><br><span class="line">   *</span><br><span class="line">   * @param className  类名</span><br><span class="line">   * @param methodName 方法名</span><br><span class="line">   * @param obj        对象</span><br><span class="line">   * @param pareTypes  参数类型</span><br><span class="line">   * @param pareValues 调用方法传入的参数</span><br><span class="line">   * @return</span><br><span class="line">   */</span><br><span class="line">  public static Object invokeMethod(String className, String methodName, Object obj, Class[] pareTypes, Object[] pareValues) &#123;</span><br><span class="line">    try &#123;</span><br><span class="line">      Class objClass = Class.forName(className);</span><br><span class="line">      Method method = objClass.getMethod(methodName, pareTypes);</span><br><span class="line">      return method.invoke(obj, pareValues);</span><br><span class="line">    &#125; catch (ClassNotFoundException | NoSuchMethodException | InvocationTargetException | IllegalAccessException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    return null;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 反射得到类的属性（包括私有和保护）</span><br><span class="line">   *</span><br><span class="line">   * @param className 类名</span><br><span class="line">   * @param obj       对象</span><br><span class="line">   * @param fieldName 属性名</span><br><span class="line">   * @return</span><br><span class="line">   */</span><br><span class="line">  public static Object getFieldObject(String className, Object obj, String fieldName) &#123;</span><br><span class="line">    try &#123;</span><br><span class="line">      Class objClass = Class.forName(className);</span><br><span class="line">      Field field = objClass.getDeclaredField(fieldName);</span><br><span class="line">      field.setAccessible(true);</span><br><span class="line">      return field.get(obj);</span><br><span class="line">    &#125; catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    return null;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 反射得到类的静态属性（包括私有和保护）</span><br><span class="line">   *</span><br><span class="line">   * @param className 类名</span><br><span class="line">   * @param fieldName 属性名</span><br><span class="line">   * @return</span><br><span class="line">   */</span><br><span class="line">  public static Object getStaticFieldObject(String className, String fieldName) &#123;</span><br><span class="line">    try &#123;</span><br><span class="line">      Class objClass = Class.forName(className);</span><br><span class="line">      Field field = objClass.getDeclaredField(fieldName);</span><br><span class="line">      field.setAccessible(true);</span><br><span class="line">      return field.get(null);</span><br><span class="line">    &#125; catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    return null;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 设置类的属性（包括私有和保护）</span><br><span class="line">   *</span><br><span class="line">   * @param className  类名</span><br><span class="line">   * @param fieldName  属性名</span><br><span class="line">   * @param obj        对象</span><br><span class="line">   * @param fieldValue 字段值</span><br><span class="line">   */</span><br><span class="line">  public static void setFieldObject(String className, String fieldName, Object obj, Object fieldValue) &#123;</span><br><span class="line">    try &#123;</span><br><span class="line">      Class objClass = Class.forName(className);</span><br><span class="line">      Field field = objClass.getDeclaredField(fieldName);</span><br><span class="line">      field.setAccessible(true);</span><br><span class="line">      field.set(obj, fieldValue);</span><br><span class="line">    &#125; catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 设置类的静态属性（包括私有和保护）</span><br><span class="line">   *</span><br><span class="line">   * @param className  类名</span><br><span class="line">   * @param fieldName  属性名</span><br><span class="line">   * @param fieldValue 属性值</span><br><span class="line">   */</span><br><span class="line">  public static void setStaticObject(String className, String fieldName, String fieldValue) &#123;</span><br><span class="line">    try &#123;</span><br><span class="line">      Class objClass = Class.forName(className);</span><br><span class="line">      Field field = objClass.getDeclaredField(fieldName);</span><br><span class="line">      field.setAccessible(true);</span><br><span class="line">      field.set(null, fieldValue);</span><br><span class="line">    &#125; catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>######4). MainActivity<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">public class MainActivity extends AppCompatActivity &#123;</span><br><span class="line">  </span><br><span class="line">  private static final String TAG=MainActivity.class.getSimpleName();</span><br><span class="line">  @Override</span><br><span class="line">  protected void onCreate(Bundle savedInstanceState) &#123;</span><br><span class="line">    super.onCreate(savedInstanceState);</span><br><span class="line">    setContentView(R.layout.activity_main);</span><br><span class="line">    Log.d(TAG,&quot;-------------onCreate&quot;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>######5). AndroidManifest.xml文件<br>在这个文件中，需要配置meta-data结点和将源apk中四大组件进行配置，否则无法运行源apk中的内容<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span><br><span class="line">&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;</span><br><span class="line">          package=&quot;com.mazaiting.reforceapk&quot;&gt;</span><br><span class="line"></span><br><span class="line">  &lt;application</span><br><span class="line">      android:name=&quot;.ProxyApplication&quot;</span><br><span class="line">      android:allowBackup=&quot;true&quot;</span><br><span class="line">      android:icon=&quot;@mipmap/ic_launcher&quot;</span><br><span class="line">      android:label=&quot;@string/app_name&quot;</span><br><span class="line">      android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;</span><br><span class="line">      android:supportsRtl=&quot;true&quot;</span><br><span class="line">      android:theme=&quot;@style/AppTheme&quot;&gt;</span><br><span class="line">    &lt;meta-data</span><br><span class="line">        android:name=&quot;APPLICATION_CLASS_NAME&quot;</span><br><span class="line">        android:value=&quot;com.mazaiting.reinforcement.SourceApplication&quot;/&gt;</span><br><span class="line">    &lt;activity android:name=&quot;com.mazaiting.reinforcement.MainActivity&quot;&gt;</span><br><span class="line">      &lt;intent-filter&gt;</span><br><span class="line">        &lt;action android:name=&quot;android.intent.action.MAIN&quot;/&gt;</span><br><span class="line"></span><br><span class="line">        &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot;/&gt;</span><br><span class="line">      &lt;/intent-filter&gt;</span><br><span class="line">    &lt;/activity&gt;</span><br><span class="line">    &lt;activity android:name=&quot;com.mazaiting.reinforcement.SecondActivity&quot;&gt;</span><br><span class="line">    &lt;/activity&gt;</span><br><span class="line">  &lt;/application&gt;</span><br><span class="line"></span><br><span class="line">&lt;/manifest&gt;</span><br></pre></td></tr></table></figure></p>
<p>######6). 打包<br>与源apk相同，对此Module进行打包，打包完成后，更改文件后缀名apk为zip，使用压缩工具解压，将解压后文件夹中的classes.dex文件复制到项目根目录force文件夹下<br><img src="https://upload-images.jianshu.io/upload_images/3110861-0e9bed3e7bed93c4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图5.png"><br><img src="https://upload-images.jianshu.io/upload_images/3110861-0657ef7a7e095569.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图6.png"><br><img src="https://upload-images.jianshu.io/upload_images/3110861-60ae83dfbed3b90b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图7.png"></p>
<p>####4. 加密工程</p>
<p>######1). 新建一个Java Module</p>
<p>######2). 加密步骤<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">* 步骤：</span><br><span class="line">*    1. 获取待加密的APK, 并对其二进制数据加密</span><br><span class="line">*    2. 取出壳DEX, 并获取其二进制数据</span><br><span class="line">*    3. 计算拼接后的DEX应用的大小, 并创建二进制数组</span><br><span class="line">*    4. 依次将解壳DEX,加密后的源APK,加密后的源APK大小,拼接出新的DEX</span><br><span class="line">*    5. 修改DEX的头，fileSize字段</span><br><span class="line">*    6. 修改DEX的头，SHA1字段</span><br><span class="line">*    7. 修改DEX的头，CheckNum字段</span><br><span class="line">*    8. 输出新的DEX文件</span><br></pre></td></tr></table></figure></p>
<p>######3). DexShellTool<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 加密APK</span><br><span class="line"> * 步骤：</span><br><span class="line"> *    1. 获取待加密的APK, 并对其二进制数据加密</span><br><span class="line"> *    2. 取出壳DEX, 并获取其二进制数据</span><br><span class="line"> *    3. 计算拼接后的DEX应用的大小, 并创建二进制数组</span><br><span class="line"> *    4. 依次将解壳DEX,加密后的源APK,加密后的源APK大小,拼接出新的DEX</span><br><span class="line"> *    5. 修改DEX的头，fileSize字段</span><br><span class="line"> *    6. 修改DEX的头，SHA1字段</span><br><span class="line"> *    7. 修改DEX的头，CheckNum字段</span><br><span class="line"> *    8. 输出新的DEX文件</span><br><span class="line"> */</span><br><span class="line">public class DexShellTool &#123;</span><br><span class="line">  public static void main(String[] args) &#123;</span><br><span class="line">    try &#123;</span><br><span class="line">      // 需要加壳的源APK, 以二进制形式读取，并进行加密处理</span><br><span class="line">      File srcApkFile = new File(&quot;force/source.apk&quot;);</span><br><span class="line">      System.out.println(&quot;apk path: &quot; + srcApkFile.getAbsolutePath());</span><br><span class="line">      System.out.println(&quot;apk size: &quot; + srcApkFile.length());</span><br><span class="line">      // 加密并返回元apk数据</span><br><span class="line">      byte[] enSrcApkArray = encrypt(readFileBytes(srcApkFile));</span><br><span class="line">      </span><br><span class="line">      // 需要解壳的dex, 以二进制形式读出dex</span><br><span class="line">      File unShellDexFile = new File(&quot;force/shell.dex&quot;);</span><br><span class="line">      byte[] unShellDexArray = readFileBytes(unShellDexFile);</span><br><span class="line">      </span><br><span class="line">      // 将源APK长度和需要解壳的DEX长度相加并加上存放源APK大小的四位得到总长度</span><br><span class="line">      int enSrcApkLen = enSrcApkArray.length;</span><br><span class="line">      int unShellDexLen = unShellDexArray.length;</span><br><span class="line">      // 多出的四位存放加密后的dex长度</span><br><span class="line">      int totalLen = enSrcApkLen + unShellDexLen + 4;</span><br><span class="line">      </span><br><span class="line">      // 依次将解壳DEX,加密后的源APK,加密后的源APK大小,拼接出新的DEX</span><br><span class="line">      byte[] newDex = new byte[totalLen];</span><br><span class="line">      // 复制加壳数据</span><br><span class="line">      System.arraycopy(unShellDexArray, 0, newDex, 0, unShellDexLen);</span><br><span class="line">      // 复制加密apk数据</span><br><span class="line">      System.arraycopy(enSrcApkArray, 0, newDex, unShellDexLen, enSrcApkLen);</span><br><span class="line">      // 赋值加壳后的dex大小</span><br><span class="line">      System.arraycopy(intToByte(enSrcApkLen), 0, newDex, totalLen - 4, 4);</span><br><span class="line">      </span><br><span class="line">      // 修改DEX file size 文件头</span><br><span class="line">      fixFileSizeHeader(newDex);</span><br><span class="line">      // 修改DEX SHA1 文件头</span><br><span class="line">      fixSHA1Header(newDex);</span><br><span class="line">      // 修改DEX CheckNum文件头</span><br><span class="line">      fixCheckSumHeader(newDex);</span><br><span class="line">      </span><br><span class="line">      // 写出新的DEX</span><br><span class="line">      String str = &quot;force/classes.dex&quot;;</span><br><span class="line">      File file = new File(str);</span><br><span class="line">      if (!file.exists()) &#123;</span><br><span class="line">        file.createNewFile();</span><br><span class="line">      &#125;</span><br><span class="line">      FileOutputStream fos = new FileOutputStream(str);</span><br><span class="line">      fos.write(newDex);</span><br><span class="line">      fos.flush();</span><br><span class="line">      fos.close();</span><br><span class="line">      </span><br><span class="line">    &#125; catch (IOException | NoSuchAlgorithmException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 修改DEX头，CheckSum校验码</span><br><span class="line">   *</span><br><span class="line">   * @param dexBytes 要修改的二进制数据</span><br><span class="line">   */</span><br><span class="line">  private static void fixCheckSumHeader(byte[] dexBytes) &#123;</span><br><span class="line">    Adler32 adler = new Adler32();</span><br><span class="line">    // 从12到文件末尾计算校验码</span><br><span class="line">    adler.update(dexBytes, 12, dexBytes.length - 12);</span><br><span class="line">    long value = adler.getValue();</span><br><span class="line">    int va = (int) value;</span><br><span class="line">    byte[] newCs = intToByte(va);</span><br><span class="line">    // 高低位互换位置</span><br><span class="line">    byte[] reCs = new byte[4];</span><br><span class="line">    for (int i = 0; i &lt; 4; i++) &#123;</span><br><span class="line">      reCs[i] = newCs[newCs.length - 1 - i];</span><br><span class="line">      System.out.println(&quot;fixCheckSumHeader:&quot; + Integer.toHexString(newCs[i]));</span><br><span class="line">    &#125;</span><br><span class="line">    // 校验码赋值（8-11）</span><br><span class="line">    System.arraycopy(reCs, 0, dexBytes, 8, 4);</span><br><span class="line">    System.out.println(&quot;fixCheckSumHeader:&quot; + Long.toHexString(value));</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 修改DEX头， sha1值</span><br><span class="line">   *</span><br><span class="line">   * @param dexBytes 要修改的二进制数组</span><br><span class="line">   */</span><br><span class="line">  private static void fixSHA1Header(byte[] dexBytes) throws NoSuchAlgorithmException &#123;</span><br><span class="line">    MessageDigest md = MessageDigest.getInstance(&quot;SHA-1&quot;);</span><br><span class="line">    // 从32位到结束计算sha-1</span><br><span class="line">    md.update(dexBytes, 32, dexBytes.length - 32);</span><br><span class="line">    byte[] newDt = md.digest();</span><br><span class="line">    // 修改sha-1值（12-21）</span><br><span class="line">    System.arraycopy(newDt, 0, dexBytes, 12, 20);</span><br><span class="line">    // 输出sha-1值</span><br><span class="line">    StringBuilder hexStr = new StringBuilder();</span><br><span class="line">    for (byte aNewDt : newDt) &#123;</span><br><span class="line">      hexStr.append(Integer.toString((aNewDt &amp; 0xFF) + 0x100, 16).substring(1));</span><br><span class="line">    &#125;</span><br><span class="line">    System.out.println(&quot;fixSHA1Header:&quot; + hexStr.toString());</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 修改DEX头， file_size值</span><br><span class="line">   *</span><br><span class="line">   * @param dexBytes 二进制数据</span><br><span class="line">   */</span><br><span class="line">  private static void fixFileSizeHeader(byte[] dexBytes) &#123;</span><br><span class="line">    // 新文件长度</span><br><span class="line">    byte[] newFs = intToByte(dexBytes.length);</span><br><span class="line">    System.out.println(&quot;fixFileSizeHeader: &quot; + Integer.toHexString(dexBytes.length));</span><br><span class="line">    byte[] reFs = new byte[4];</span><br><span class="line">    // 高低位换位置</span><br><span class="line">    for (int i = 0; i &lt; 4; i++) &#123;</span><br><span class="line">      reFs[i] = newFs[newFs.length - 1 - i];</span><br><span class="line">      System.out.println(&quot;fixFileSizeHeader: &quot; + Integer.toHexString(newFs[i]));</span><br><span class="line">    &#125;</span><br><span class="line">    // 修改32-35</span><br><span class="line">    System.arraycopy(reFs, 0, dexBytes, 32, 4);</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * int 转 byte[]</span><br><span class="line">   *</span><br><span class="line">   * @param number 整型</span><br><span class="line">   * @return 返回字节数组</span><br><span class="line">   */</span><br><span class="line">  private static byte[] intToByte(int number) &#123;</span><br><span class="line">    byte[] b = new byte[4];</span><br><span class="line">    for (int i = 3; i &gt;= 0; i--) &#123;</span><br><span class="line">      b[i] = (byte) (number % 256);</span><br><span class="line">      number &gt;&gt;= 8;</span><br><span class="line">    &#125;</span><br><span class="line">    return b;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 加密二进制数据</span><br><span class="line">   *</span><br><span class="line">   * @param srcData 字节数组</span><br><span class="line">   * @return 加密后的二进制数组</span><br><span class="line">   */</span><br><span class="line">  private static byte[] encrypt(byte[] srcData) &#123;</span><br><span class="line">    for (int i = 0; i &lt; srcData.length; i++) &#123;</span><br><span class="line">      srcData[i] ^= 0xFF;</span><br><span class="line">    &#125;</span><br><span class="line">    return srcData;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  /**</span><br><span class="line">   * 以二进制读出文件内容</span><br><span class="line">   *</span><br><span class="line">   * @param file 文件</span><br><span class="line">   * @return 二进制数据</span><br><span class="line">   */</span><br><span class="line">  private static byte[] readFileBytes(File file) throws IOException &#123;</span><br><span class="line">    byte[] bytes = new byte[1024];</span><br><span class="line">    ByteArrayOutputStream baos = new ByteArrayOutputStream();</span><br><span class="line">    FileInputStream fis = new FileInputStream(file);</span><br><span class="line">    while (true) &#123;</span><br><span class="line">      int len = fis.read(bytes);</span><br><span class="line">      if (-1 == len) break;</span><br><span class="line">      baos.write(bytes, 0, len);</span><br><span class="line">    &#125;</span><br><span class="line">    byte[] byteArray = baos.toByteArray();</span><br><span class="line">    fis.close();</span><br><span class="line">    baos.close();</span><br><span class="line">    return byteArray;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>######4). 运行main函数<br>在项目的根目录的force文件夹下，生成一个classes.dex文件<br><img src="https://upload-images.jianshu.io/upload_images/3110861-343da0fd7b7f4b1f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图8.png"></p>
<p>####5. 合并</p>
<p>######1). 项目结构<br><img src="https://upload-images.jianshu.io/upload_images/3110861-1a824528a41d5526.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图9.png"></p>
<p>######2). 收集文件<br>将force/classes.dex与reforceapk Module生成的apk放在桌面<br><img src="https://upload-images.jianshu.io/upload_images/3110861-9b2e9fb6ecb5198d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图10.png"></p>
<p>######3). 替换<br>将reforceapk-release.apk直接使用压缩工具打开，将classes.dex复制并替换reforceapk-release.apk中原有的classes.dex文件.<br><img src="https://upload-images.jianshu.io/upload_images/3110861-d958a836f5f45ca6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="图11.png"></p>
<p>######4). 重签名<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">jarsigner -verbose -keystore E:\android\key\release-key.keystore -storepass mazaiting -keypass mazaiting -sigfile CERT -digestalg SHA1 -sigalg MD5withRSA -signedjar Reforce_des.apk reforceapk-release.apk key-alias</span><br><span class="line">del reforceapk-release.apk</span><br></pre></td></tr></table></figure></p>
<p>参数说明：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jarsigner -verbose -keystore 签名文件 -storepass 密码  -keypass alias的密码 -sigfile CERT -digestalg SHA1 -sigalg MD5withRSA  签名后的文件 签名前的apk alias名称</span><br></pre></td></tr></table></figure></p>
<p>######5). 安装运行<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">adb install C:\Users\mazaiting\Desktop\Reforce_des.apk</span><br></pre></td></tr></table></figure></p>
<p>####7. 参考文章及代码</p>
<ul>
<li>文章<br><a href="https://blog.csdn.net/jiangwei0910410003/article/details/48415225" target="_blank" rel="noopener">Android中的Apk的加固(加壳)原理解析和实现</a></li>
<li>代码<br><a href="https://github.com/huyuxin95/DexShellProject" target="_blank" rel="noopener">DexShellProject</a><br>####6. 残留的问题</li>
<li>源APP中Activity中的界面组件是由代码构建，xml文件中如何加载？</li>
<li>宿主APP中ProxyApplication中使用到了源APP中的入口Application及MainActivity，如何动态获取？</li>
<li>宿主APP中AndroidManifest.xml文件中需要配置源APP的四大组件，如何不进行不配置？</li>
</ul>
<p>####<a href="https://gitee.com/mazaiting/app_protection/tree/master/Reinforcement" target="_blank" rel="noopener">代码下载</a></p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/blog/2018/08/06/Android-JNI/Android-JNI相关/" rel="next" title="Android-JNI相关">
                <i class="fa fa-chevron-left"></i> Android-JNI相关
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/blog/2018/08/06/Android-Plugin/Android-动态加载DEX/" rel="prev" title="Android-动态加载DEX">
                Android-动态加载DEX <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      

      <section class="site-overview-wrap sidebar-panel sidebar-panel-active">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image"
                src="/blog/images/avatar.jpeg"
                alt="凌浩雨" />
            
              <p class="site-author-name" itemprop="name">凌浩雨</p>
              <p class="site-description motion-element" itemprop="description">专业从事于移动端开发，Android与iOS均有涉及，主做Android开发与React Native开发</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/blog/archives/">
              
                  <span class="site-state-item-count">393</span>
                  <span class="site-state-item-name">posts</span>
                </a>
              </div>
            

            

            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">凌浩雨</span>

  
</div>


  <div class="powered-by">Powered by <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a></div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">Theme &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Pisces</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/blog/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/blog/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/blog/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/blog/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/blog/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/blog/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/blog/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>
